package se.webbzon.boltzmann.game.event;

import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.game.object.waypoint.AbstractDirection;
import se.webbzon.boltzmann.game.object.waypoint.DirectionListener;
import se.webbzon.boltzmann.game.object.waypoint.NPCDirection;
import se.webbzon.boltzmann.game.object.waypoint.PlayerDirection;
import se.webbzon.boltzmann.game.object.waypoint.Waypoint;
import se.webbzon.boltzmann.game.sequence.Sequence;
import se.webbzon.boltzmann.npc.AbstractNPC;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldobject.WorldObject;
import se.webbzon.oschi01.worldobject.WorldStaticObject;

public class WalkToEvent extends AbstractTargetEvent {
	
	// The world object associated with this walk event
	private final WorldObject binding;
	
	// Wait until the direction is complete
	private final boolean wait;
	
	// Destroy the instance when the path is complete
	private final boolean destroy;
	
	// The waypoint used for moving
	private Waypoint waypoint;
	
	// The direction of this walk event
	private AbstractDirection direction;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public WalkToEvent(Sequence sequence, WorldObject binding, String[] arguments, boolean wait, boolean destroy) {
		super(sequence,arguments);
		this.binding = binding;
		this.wait = wait;
		this.destroy = destroy;
	}
	
	/*============================================================
	Public Methods
	============================================================*/

	@Override protected void onBegin(WorldArea world) {
		WorldObject target = getTarget();
		if (target instanceof Waypoint) {
			waypoint = (Waypoint) target;
		} else if (target instanceof WorldStaticObject) {
			WorldStaticObject wso = (WorldStaticObject) target;
			waypoint = new Waypoint(getSequence().getEnvironment());
			waypoint.setPosition(wso.getX(), wso.getY(), wso.getZ());
		} else {
			end();
			return;
		}
		
		if (binding instanceof AbstractPlayerCharacter) {
			AbstractPlayerCharacter player = (AbstractPlayerCharacter) binding;
			direction = new PlayerDirection(player,waypoint);
		} else if (binding instanceof AbstractNPC) {
			AbstractNPC npc = (AbstractNPC) binding;
			direction = new NPCDirection(npc,waypoint);
		}
		
		if (direction == null)
			end();
		else if (!wait) {
			direction.begin(world);
			direction.addListener(new DirectionListenerImpl());
			end();
		} else {
			direction.begin(world);
			direction.addListener(new DirectionListenerImpl());
		}
	}

	@Override protected void onEnd() {
		if (wait && direction != null)
			direction.end(getSequence().getWorld());
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private final class DirectionListenerImpl implements DirectionListener {

		@Override public void targetReached(AbstractDirection direction) {
			if (wait)
				end();
			if (destroy) {
				WorldObject directionTaker = direction.getDirectionTaker();
				WorldArea world = directionTaker.getWorld();
				if (world != null)
					world.destroyInstance(directionTaker);
			}
		}
		
	}

}
